﻿namespace AssemblyProvider.Web
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.ComponentModel.DataAnnotations;
    using System.Linq;
    using System.ServiceModel.DomainServices.Hosting;
    using System.ServiceModel.DomainServices.Server;
    using AssemblyProvider.Web.Entities;
    using AbstraX.ServerInterfaces;
    using System.IO;
    using System.Diagnostics;
    using MvvmTreeView;
    using System.Threading;
    using AbstraX.Contracts;
    using AbstraX.AssemblyInterfaces;
    using AbstraX.Bindings;
    using AbstraX.TypeMappings;
    using AbstraX;
    using Microsoft.Practices.Unity;

    /*
        AssembliesRoot
          Assembly
            Type

              ---- Attributes

                     PropertyAttribute

              ---- Operations

                     ConstructorOperation
                     MethodOperation

              ---- ChildElements

                     PropertyElement
                       TypeElement
     */

    [EnableClientAccess()]
    public class AssemblyProviderService : AbstraXDomainService, IAssemblyProviderService
    {
        public AssembliesRoot GetAssembliesRoot()
        {
            return new AssembliesRoot(this.DomainServiceHostApplication);
        }

        public IAssembliesRoot GetAssembliesRoot(List<string> assemblies)
        {
            return new AssembliesRoot(this.DomainServiceHostApplication, assemblies);
        }

        [Invoke]
        public override string GetQueryMethodForID(string id)
        {
            return AbstraXExtensions.GetQueryMethodForID(this, id);
        }

        [Invoke]
        public override string GetRootID()
        {
            return new AssembliesRoot(this.DomainServiceHostApplication).ID;
        }

        [Query]
        public IQueryable<Assembly> GetAssemblies()
        {
            var hierarchy = new AssemblyProviderHierarchy<Assembly>(this.DomainServiceHostApplication);
            var results = hierarchy.AsQueryable();

            return results;
        }

        [Query]
        public IQueryable<Entities.AssemblyType> GetTypes()
        {
            var hierarchy = new AssemblyProviderHierarchy<Entities.AssemblyType>(this.DomainServiceHostApplication);
            var results = hierarchy.AsQueryable();

            return results;
        }

        [Query]
        public IQueryable<PropertyElement> GetPropertyElements()
        {
            var hierarchy = new AssemblyProviderHierarchy<PropertyElement>(this.DomainServiceHostApplication);
            var results = hierarchy.AsQueryable();

            return results;
        }

        [Query]
        public IQueryable<PropertyAttribute> GetPropertyAttributes()
        {
            var hierarchy = new AssemblyProviderHierarchy<PropertyAttribute>(this.DomainServiceHostApplication);
            var results = hierarchy.AsQueryable();

            return results;
        }

        [Query]
        public IQueryable<FieldAttribute> GetFieldAttributes()
        {
            var hierarchy = new AssemblyProviderHierarchy<FieldAttribute>(this.DomainServiceHostApplication);
            var results = hierarchy.AsQueryable();

            return results;
        }

        [Query]
        public IQueryable<Operation> GetOperations()
        {
            var hierarchy = new AssemblyProviderHierarchy<Operation>(this.DomainServiceHostApplication);
            var results = hierarchy.AsQueryable();

            return results;
        }

        [Query]
        public IQueryable<Assembly> GetAssembliesForAssembliesRoot(string parentID)
        {
            var hierarchy = new AssemblyProviderHierarchy<Assembly>(this.DomainServiceHostApplication);
            var results = hierarchy.AsQueryable().Where(a => a.ParentID == parentID);

            return results;
        }

        [Query, AbstraXProviderMessageInspectorOperationBehaviorAttribute]
        public IQueryable<Entities.AssemblyType> GetTypesForAssembly(string parentID)
        {
            var hierarchy = new AssemblyProviderHierarchy<Entities.AssemblyType>(this.DomainServiceHostApplication, parentID);
            var results = hierarchy.AsQueryable().Where(t => t.ParentID == parentID);

            return results;
        }

        [Query]
        public IQueryable<Entities.AssemblyType> GetTypesForAssemblyType(string parentID)
        {
            var hierarchy = new AssemblyProviderHierarchy<Entities.AssemblyType>(this.DomainServiceHostApplication, parentID);
            var results = hierarchy.AsQueryable().Where(t => t.ParentID == parentID);

            return results;
        }

        [Query]
        public IQueryable<PropertyElement> GetPropertyElementsForAssemblyType(string parentID)
        {
            var hierarchy = new AssemblyProviderHierarchy<PropertyElement>(this.DomainServiceHostApplication, parentID);
            var results = hierarchy.AsQueryable().Where(t => t.ParentID == parentID);

            return results;
        }

        [Query]
        public IQueryable<PropertyAttribute> GetPropertyAttributesForAssemblyType(string parentID)
        {
            var hierarchy = new AssemblyProviderHierarchy<PropertyAttribute>(this.DomainServiceHostApplication, parentID);
            var results = hierarchy.AsQueryable().Where(t => t.ParentID == parentID);

            return results;
        }

        [Query]
        public IQueryable<FieldAttribute> GetFieldAttributesForAssemblyType(string parentID)
        {
            var hierarchy = new AssemblyProviderHierarchy<FieldAttribute>(this.DomainServiceHostApplication, parentID);
            var results = hierarchy.AsQueryable().Where(t => t.ParentID == parentID);

            return results;
        }

        [Query]
        public IQueryable<Operation> GetOperationsForAssemblyType(string parentID)
        {
            var hierarchy = new AssemblyProviderHierarchy<Operation>(this.DomainServiceHostApplication, parentID);
            var results = hierarchy.AsQueryable().Where(t => t.ParentID == parentID);

            return results;
        }

        [Query]
        public IQueryable<Entities.AssemblyType> GetTypesForMethodOperation(string parentID)
        {
            var hierarchy = new AssemblyProviderHierarchy<Entities.AssemblyType>(this.DomainServiceHostApplication, parentID);
            var results = hierarchy.AsQueryable().Where(t => t.ParentID == parentID);

            return results;
        }

        [Query]
        public IQueryable<Entities.AssemblyType> GetTypesForPropertyElement(string parentID)
        {
            var hierarchy = new AssemblyProviderHierarchy<Entities.AssemblyType>(this.DomainServiceHostApplication, parentID);
            var results = hierarchy.AsQueryable().Where(t => t.ParentID == parentID);

            return results;
        }

        [Invoke]
        public override byte[] GetImageForFolder(string folderKey)
        {
            var stream = this.GetType().Assembly.GetManifestResourceStream(folderKey);
            var bytes = new byte[stream.Length];

            stream.Read(bytes, 0, (int)stream.Length);

            return bytes;
        }

        [Invoke]
        public override byte[] GetImageForItemType(string itemTypeName)
        {
            var attribute = (NodeImageAttribute) System.Type.GetType(itemTypeName).GetCustomAttributes(true).FirstOrDefault(a => a is NodeImageAttribute);

            var stream = this.GetType().Assembly.GetManifestResourceStream(attribute.ImagePath);
            var bytes = new byte[stream.Length];

            stream.Read(bytes, 0, (int) stream.Length);

            return bytes;
        }

        [Invoke]
        public override byte[] GetImageForUrl(string url)
        {
            var stream = this.GetType().Assembly.GetManifestResourceStream(url);
            var bytes = new byte[stream.Length];

            stream.Read(bytes, 0, (int)stream.Length);

            return bytes;
        }

        public override IBase GenerateByID(string id)
        {
            return AbstraXExtensions.GenerateByID(this, id);
        }

        public override ContainerType GetAllowableContainerTypes(string id)
        {
            var baseObject = AbstraXExtensions.GenerateByID(this, id);

            throw new NotImplementedException();
        }

        public override ConstructType GetAllowableConstructTypes(string id)
        {
            var baseObject = AbstraXExtensions.GenerateByID(this, id);

            throw new NotImplementedException();
        }

        public override SortedList<float, IPipelineStep> InitialPipelineSteps
        {
            get 
            {
                var step = this.DomainServiceHostApplication.PipelineContainer.Resolve<IPipelineStep>("CsParserStep");
                var list = new SortedList<float, IPipelineStep>();

                list.Add(0, step);

                return list;
            }
        }

        public override void ClearCache()
        {
            AssemblyProviderHierarchy<IBase>.ClearCache();
        }
    }
}


